[ORG 0X500]

[SECTION .data]
KERNEL_ADDR equ 0x1200
[SECTION .gdt]

SEG_BASE equ 0x00000000   ;BASE地址在GDT中占32位
SEG_LIMIT equ 0xfffff     ;LIMIT地址限制在GDT中占20位

CODE_SELECTOR equ (1 << 3)
DATA_SELECTOR equ (2 << 3)

gdt_base:
    dd 0,0
gdt_code:
    dw SEG_LIMIT & 0xffff
    dw SEG_BASE & 0xffff
    db (SEG_BASE >> 16) & 0xff
    ;    P_DPL_S_TYPE
    db  0b1_00_1_1000
    ;    G_DB_AVL_LIMIT
    db 0b0_1_00_0000 | (SEG_LIMIT >> 16 & 0xf)
    db SEG_BASE >> 24 & 0xf

gdt_data:
     dw SEG_LIMIT & 0xffff
     dw SEG_BASE & 0xffff
     db (SEG_BASE >> 16) & 0xff
     ;    P_DPL_S_TYPE
     db  0b1_00_1_0010
     ;    G_DB_AVL_LIMIT
     db 0b1_1_00_0000 | (SEG_LIMIT >> 16 & 0xf)
     db SEG_BASE >> 24 & 0xf

gdt_ptr:
     dw $ - gdt_base
     dd gdt_base


[SECTION .text]
[BITS 16]

global _start

_start:
    mov     ax, 0
    mov     ss, ax
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax
    mov     si, ax

    mov     si, prepare_enter_protected_mode_msg
    call    print

enter_protected_mode:
    ; 关中断
    cli
    ; 加载GDT表
    lgdt   [gdt_ptr]

    in      al, 92h
    or      al, 0b0000_000_1_0
    out     92h, al

    mov     eax, cr0
    or      eax, 1
    mov     cr0,eax

    jmp     CODE_SELECTOR:protected_mode
; 如何调用
; mov     si, msg   ; 1 传入字符串
; call    print     ; 2 调用
print:
    mov ah, 0x0e
    mov bh, 0
    mov bl, 0x01
.loop:
    mov al, [si]
    cmp al, 0
    jz .done
    int 0x10

    inc si
    jmp .loop
.done:
    ret


[BITS 32]
protected_mode:

    mov     ax, DATA_SELECTOR
    mov     ss, ax
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax

    mov esp, 0x9fbff

    ; 将内核读入内存
    mov edi, KERNEL_ADDR
    mov ecx, 3
    mov bl, 60
    call read_hd

    jmp CODE_SELECTOR:KERNEL_ADDR

read_hd:
    ;0x1f2  8个bit位指定读取的扇区数量
    mov     dx, 0x1f2
    mov     al, bl
    out     dx, al

    ;0x1f3  8个bit位 表示IBA的低八位地址 0-7
    inc     dx
    mov     al, cl
    out     dx, al

    ;0x1f4  8个bit位 表示IBA的中八位地址 8-15
    inc     dx
    mov     al, ch
    out     dx, al

    ;0x1f5  8个bit位 表示IBA的高八位地址 16-23
    inc     dx
    shr     ecx, 16
    mov     al, cl
    out     dx, al

    ;0x1f6  8个bit位 表示IBA的中八位地址 8-15
    ; 0-3 位iba地址的24-27
    ; 4 0表示主盘 1表示从盘
    ; 5、7位固定为1
    ; 6 0表示CHS模式，1表示LAB模式
    inc dx
    shr ecx, 8
    and cl, 0b1111
    mov al, 0b1110_0000     ; LBA模式
    or al, cl
    out dx, al

    ;0x1f7  命令或者状态端口
    inc     dx
    mov     al, 0x20
    out     dx, al

    ; 设置loop次数，读多少个扇区要loop多少次
    mov cl, bl
.start_read:
    push cx     ; 保存loop次数，防止被下面的代码修改破坏

    call .wait_hd_prepare
    call read_hd_data

    pop cx      ; 恢复loop次数

    loop .start_read

.return:
    ret

; 一直等待，直到硬盘的状态是：不繁忙，数据已准备好
; 即第7位为0，第3位为1，第0位为0
.wait_hd_prepare:
    mov     dx, 0x1f7
.check:

    in      al, dx
    and     al, 0b1000_1000
    cmp     al, 0b0000_1000
    jnz     .check
    ret
read_hd_data:
    ;读数据
    mov     dx, 0x1f0
    mov     cx, 256


.read_word:
    in      ax, dx
    mov     [edi], ax
    add     edi, 2
    loop    .read_word

    ret


msg:
    db "hello, world", 10, 13, 0

prepare_enter_protected_mode_msg:
    db "Prepare to go into protected mode...", 10, 13, 0
